﻿using System;
using System.Collections.Generic;
using System.Collections;
using Bling;
using Semantics = Bling.Semantics;
using Bling.Util;
using Bling.DSL;
using Bling.Properties;
using Bling.Core;
using Bling.Mixins;

// only talk about vertices, support instancing. 
namespace Bling.Vertices {
  public interface IVertexBuffer {}
  public interface IVertexBuffer<BUFFER> : IVertexBuffer, IHasMixin<BUFFER> where BUFFER : IVertexBuffer<BUFFER> {}
  public abstract class VertexBuffer : IVertexBuffer, IListBl<VertexBuffer.Vertex> {
    public readonly List<int> Indices = new List<int>();

    public interface IProperty : Properties.IProperty {
      Semantics.Role Semantic { get; }
      bool IsDynamic { get; }
    }
    public interface IPerVertex : IProperty { }
    public interface IPerInstance : IProperty {
      Instanced Instance { get; } 
    }
    public abstract class Vertex : IPropertyContainer {
    }
    public Vertex this[IntBl Idx] {
      get { return GetVertex(Idx); }
    }
    public Vertex this[Instanced instance, IntBl Idx] {
      get { return GetVertex(instance, Idx); }
    }

    public Action<Vertex> ForAll { set { value(this[new LoopIndexExpr(this, Count)]); } }

    // vertex count. 
    public int Count { get; private set; }

    public VertexBuffer(int Count) {
      this.Count = Count;
    }
    protected abstract Vertex GetVertex(IntBl Idx);
    protected abstract Vertex GetVertex(Instanced instanced, IntBl Idx);
    // acts like a superblock. 
    public abstract class Instanced {
      public int Count { get; internal set; }
      public int Step { get; internal set; }
      public Instanced(int Count, int Step) {
        this.Count = Count; this.Step = Step;
      }
    }
    public void Triangle(int a, int b, int c) {
      Indices.Add(a, b, c);
    }

    // create triangles around start vertex.
    public int Triangles(int Start, int N) {
      (N >= 1).Assert();
      Indices.Add(Start + 0, Start + 1, Start + 2);
      var A = Start + 0;
      var B = Start + 2;
      for (int i = 1; i < N; i++) {
        var C = Start + (i + 2);
        Indices.Add(A, B, C);
        B = C;
      }
      return 3 + (N - 1);
    }
    public int Grid(int Start, int ColumnN, int RowN, Action<int, int, int> F) {
      // 0  1  2  3  ... CN
      int VertexCount = Start; // freeze it.
      Func<int, int, int> VertexAt = (ColumnM, RowM) => {
        (ColumnM <= ColumnN).Assert();
        (RowM <= RowN).Assert();
        return VertexCount + (RowM * (ColumnN + 1) + ColumnM);
      };
      if (F != null) {
        int at = VertexCount;
        for (int row = 0; row <= RowN; row++) {
          for (int col = 0; col <= ColumnN; col++) {
            (VertexAt(col, row) == at).Assert();
            F(col, row, at);
            at += 1;
          }
        }
      }
      // initialize triangle indices
      for (int col = 0; col < ColumnN; col++) {
        for (int row = 0; row < RowN; row++) {
          var A = VertexAt(col + 0, row + 1);
          var B = VertexAt(col + 0, row + 0);
          var C = VertexAt(col + 1, row + 0);
          Indices.Add(A, B, C);
          var D = VertexAt(col + 1, row + 1);
          Indices.Add(A, C, D);
        }
      }
      return RowN * ColumnN;
    }
  }
  public interface IVertexEval<EVAL> where EVAL : Eval<EVAL> {
    Eval<EVAL>.Info<T> Eval<T, BUFFER>(PropertyExpr<VertexBuffer<BUFFER>.Vertex, T> Property) where BUFFER : VertexBuffer<BUFFER>;
  }

  public abstract class VertexBuffer<BUFFER> : VertexBuffer, IVertexBuffer<BUFFER>, IListBl<VertexBuffer<BUFFER>.Vertex>, IHasMixin<BUFFER> where BUFFER : VertexBuffer<BUFFER> {
    public static readonly Dictionary<string, IProperty> Properties = new Dictionary<string, IProperty>();
    public static readonly List<IProperty> PropertiesOrdered = new List<IProperty>();
    public static readonly List<Instanced> Instances = new List<Instanced>();


    private struct FactorKey {
      public Instanced Instance;
      public bool IsDynamic;
    }

    public static List<List<IProperty>> FactorProperties() {
      Dictionary<FactorKey, int> Indices = new Dictionary<FactorKey, int>();
      var ret = new List<List<IProperty>>();
      ret.Add(new List<IProperty>());
      Indices[new FactorKey() { Instance = null, IsDynamic = false }] = 0;
      for (int i = 0; i < PropertiesOrdered.Count; i++) {
        var Prop = PropertiesOrdered[i];
        Instanced Instance;
        if (Prop is IPerInstance) {
          Instance = (Instanced)((IPerInstance)Prop).Instance;
        } else Instance = null;
        var key = new FactorKey() { Instance = Instance, IsDynamic = Prop.IsDynamic };
        if (!Indices.ContainsKey(key)) {
          Indices[key] = ret.Count;
          ret.Add(new List<IProperty>());
        }
        ret[Indices[key]].Add(Prop);
      }
      return ret;
    }


    public readonly List<IPropertyConstraint> Bindings = new List<IPropertyConstraint>();
    //public readonly List<IPropertyConstraint> Inits = new List<IPropertyConstraint>();
    public static readonly PerVertex<Point4DBl, Semantics.Position> PositionProperty = new PerVertex<Point4DBl, Semantics.Position>("Pos");

    public MixinManager<BUFFER> Mixins { get; private set; }
    public VertexBuffer(int Count) : base(Count) {
      this.Mixins = new MixinManager<BUFFER>((BUFFER)this);
    }
    public new class Instanced : VertexBuffer.Instanced {
      public Instanced(int Count, int Step) : base(Count, Step) {
        VertexBuffer<BUFFER>.Instances.Add(this);
      }
    }
    public abstract class Property<BRAND,SEMANTIC,CONTAINER> : Properties.Property<CONTAINER,BRAND>, IProperty
      where CONTAINER : IPropertyContainer<CONTAINER>
      where BRAND : Brand<BRAND> where SEMANTIC : Semantics.Role<SEMANTIC>, new() {
      public bool IsDynamic { get; set; }

      public Semantics.Role Semantic { get { return Semantics.Role<SEMANTIC>.Instance; } }

      public Property(string name) : base(name) {
        (!VertexBuffer<BUFFER>.Properties.ContainsKey(name)).Assert();
        VertexBuffer<BUFFER>.Properties[name] = this;
        VertexBuffer<BUFFER>.PropertiesOrdered.Add(this);
      }
    }
    public class PerVertex<BRAND,SEMANTIC> : Property<BRAND,SEMANTIC,Vertex>, IPerVertex
      where BRAND : Brand<BRAND>
      where SEMANTIC : Semantics.Role<SEMANTIC>, new() {
      public PerVertex(string name) : base(name) {}
    }
    public class PerInstance<BRAND, SEMANTIC> : Property<BRAND, SEMANTIC, Vertex>, IPerInstance
      where BRAND : Brand<BRAND>
      where SEMANTIC : Semantics.Role<SEMANTIC>, new() {
      public VertexBuffer.Instanced Instance { get; private set; }

      public PerInstance(string name, Instanced Instance) : base(name) { this.Instance = Instance;  }
    }


    public abstract new class Vertex : VertexBuffer.Vertex, IPropertyContainer<Vertex> {
      internal BUFFER Parent;
      internal abstract bool InShader { get; }
      public Vertex Translate<EVAL>(TranslateEval<EVAL> txt) where EVAL : Eval<EVAL> { return this; }
      internal Point4DBl UpdatedPosition;
      public Vertex() {
        UpdatedPosition = Position; // direct transfer.
      }
      public Point4DBl Position {
        get { return PositionProperty[this]; }
        set {
          if (!InShader)
            Position.Bind = value;
          else UpdatedPosition = value;
        }
      }
      public virtual Eval<EVAL>.Info<T> Eval<EVAL, T>(PropertyExpr<Vertex, T> Property, Eval<EVAL> txt) where EVAL : Eval<EVAL> {
        if (txt is IVertexEval<EVAL>)
          return ((IVertexEval<EVAL>)txt).Eval(Property);
        throw new NotSupportedException();
      }
      public bool Bind<T>(PropertyExpr<Vertex, T> Property, Expr<T> RHS) {
        if (InShader) return false;
        // we'd better be dynamic to do init, otherwise...
        // if (!((IPerVertex)Property.Property).IsDynamic) return false;
        Parent.Bindings.Add(new PropertyConstraint<Vertex, T>() {
          LHS = Property, RHS = RHS,
        });
        return true;
      }
      public bool Init<T>(PropertyExpr<Vertex, T> Property, Expr<T> RHS) {
        if (InShader) return false;
        return false; // can only bind for now.
        /*
        Parent.Inits.Add(new PropertyConstraint<Vertex, T>() {
          LHS = Property,
          RHS = RHS,
        });
        return true;
         */
      }

      /* won't support */
      public bool Link<T>(PropertyExpr<Vertex, T> Property, Expr<T> RHS, Expr<bool> Guard) { return false; }
      public bool SetNow<T>(PropertyExpr<Vertex, T> Property, T value) { return false; }
      public TDelegate SetNow<TDelegate, T>(PropertyExpr<Vertex, T> Property, Expr<T> value, IParameterExpr[] param) { throw new NotSupportedException(); }

    } 
    // used for initialization. 
    public class VertexByIndex : Vertex {
      internal override bool InShader { get { return false; } }
      public IntBl Index { get; internal set; }
      public Instanced Instance { get; internal set; }
    }

    public new Vertex this[IntBl Idx] {
      get { return new VertexByIndex() { Instance = null, Index = Idx, Parent = (BUFFER)this }; }
    }
    public Vertex this[Instanced Instance, IntBl Idx] {
      get { return new VertexByIndex() { Instance = Instance, Index = Idx, Parent = (BUFFER)this }; }
    }
    public new Action<IntBl, Vertex> ForAll {
      set {
        var Idx = new LoopIndexExpr(this, Count);
        value(Idx, this[Idx]);
      }
    }
    public void ForAllI(Instanced i, Action<IntBl,Vertex> a) {
      var Idx = new LoopIndexExpr(i, i.Count);
      a(Idx, this[i, Idx]);
    }
    protected override VertexBuffer.Vertex GetVertex(IntBl Idx) { return this[Idx]; }
    protected override VertexBuffer.Vertex GetVertex(VertexBuffer.Instanced Instance, IntBl Idx) { return this[(Instanced) Instance, Idx]; }
  }
  public class DefaultVertexBuffer : VertexBuffer<DefaultVertexBuffer> {
    public DefaultVertexBuffer(int Count) : base(Count) { }
  }

  public abstract class VertexMixin<TARGET, MIXIN> : Mixin<TARGET, MIXIN>
    where TARGET : VertexBuffer<TARGET>, IHasMixin<TARGET, MIXIN>
    where MIXIN : Mixin<TARGET, MIXIN> {
    public VertexMixin(TARGET Target) : base(Target) { }
  }
  public static class HasNormal {
    public interface IHas<TARGET> : IHasMixin<TARGET, Mixin<TARGET>> where TARGET : VertexBuffer<TARGET>, IHas<TARGET> { }
    public class Mixin<TARGET> : VertexMixin<TARGET, Mixin<TARGET>> where TARGET : VertexBuffer<TARGET>, IHas<TARGET> {
      public static VertexBuffer<TARGET>.PerVertex<Point3DBl, Semantics.Normal> NormalProperty =
        new VertexBuffer<TARGET>.PerVertex<Point3DBl, Bling.Semantics.Normal>("Normal");
      public Mixin(TARGET Target) : base(Target) { }
      public override void DoInit(TARGET Target) { }
    }
    public static Point3DBl Normal<TARGET>(this VertexBuffer<TARGET>.Vertex Vertex) where TARGET : VertexBuffer<TARGET>, IHas<TARGET> {
      return Mixin<TARGET>.NormalProperty[Vertex];
    }
  }
  public static class HasTex2D {
    public interface IHas<TARGET> : IHasMixin<TARGET, Mixin<TARGET>> where TARGET : VertexBuffer<TARGET>, IHas<TARGET> { }
    public class Mixin<TARGET> : VertexMixin<TARGET, Mixin<TARGET>> where TARGET : VertexBuffer<TARGET>, IHas<TARGET> {
      public static VertexBuffer<TARGET>.PerVertex<PointBl, Semantics.TexCoord> Tex2DProperty =
        new VertexBuffer<TARGET>.PerVertex<PointBl,Semantics.TexCoord>("T2D");
      public Mixin(TARGET Target) : base(Target) { }
      public override void DoInit(TARGET Target) { }
    }
    public static PointBl UV<TARGET>(this VertexBuffer<TARGET>.Vertex Vertex) where TARGET : VertexBuffer<TARGET>, IHas<TARGET> {
      return Mixin<TARGET>.Tex2DProperty[Vertex];
    }
  }
  public static class HasColor {
    public interface IHas<TARGET> : IHasMixin<TARGET, Mixin<TARGET>> where TARGET : VertexBuffer<TARGET>, IHas<TARGET> { }
    public class Mixin<TARGET> : VertexMixin<TARGET, Mixin<TARGET>> where TARGET : VertexBuffer<TARGET>, IHas<TARGET> {
      public static VertexBuffer<TARGET>.PerVertex<ColorBl, Semantics.Color> ColorProperty =
        new VertexBuffer<TARGET>.PerVertex<ColorBl, Semantics.Color>("Color");
      public Mixin(TARGET Target) : base(Target) { }
      public override void DoInit(TARGET Target) { }
    }
    public static ColorBl Color<TARGET>(this VertexBuffer<TARGET>.Vertex Vertex) where TARGET : VertexBuffer<TARGET>, IHas<TARGET> {
      return Mixin<TARGET>.ColorProperty[Vertex];
    }
  }
}
namespace Bling.Vertices.Shaders {
  using Bling.Shaders;
  using Bling.Vecs;

  internal enum InfoStatus {
    Pixel = 0, Vertex = 1, Uniform = 2,
  }
  internal abstract class EffectEval<EVAL> : BaseShaderEval<EVAL>, Semantics.IRoleEval<EVAL>, IDynamicEval<EVAL> where EVAL : Eval<EVAL> {
    public new interface MyInfo : BaseShaderEval<EVAL>.MyInfo {
      InfoStatus Status { get; set; }
      Semantics.Role Semantic { get; set; }
    }
    public new class MyInfo<T> : BaseShaderEval<EVAL>.MyInfo<T>, MyInfo {
      public InfoStatus Status { get; set; }
      public Semantics.Role Semantic { get; set; }
    }
    public new MyInfo<T> DoEval<T>(Expr<T> Expr) { return (MyInfo<T>)((Eval<EVAL>)this).DoEval(Expr); }

    private readonly Stack<Semantics.Role> Roles = new Stack<Bling.Semantics.Role>();
    public Eval<EVAL>.Info<T> Eval<T, ROLE>(Semantics.RoleExpr<T, ROLE> Expr) where ROLE : Semantics.Role<ROLE>, new() {
      Roles.Push(Semantics.Role<ROLE>.Instance);
      var ret = DoEval(Expr.Underlying);
      var pop = Roles.Pop();
      (pop.Equals(Semantics.Role<ROLE>.Instance)).Assert();
      return ret;
    }
    public Eval<EVAL>.Info<T> Dynamic<T>(DynamicMode Mode) {
      // bring it through as a uniform.
      var ret = (MyInfo<T>)NewInfo<T>(null);
      ret.Status = InfoStatus.Uniform;
      return ret;
    }
    public override BaseShaderEval<EVAL>.MyInfo<T> NewInfo<T>(string Value, Eval<EVAL>.Info Copy) {
      var Copy0 = (MyInfo)Copy;
      return new MyInfo<T>() { Value = Value, Semantic = Copy0.Semantic, Status = Copy0.Status };
    }
    public override BaseShaderEval<EVAL>.MyInfo<T> NewInfo<T>(string Value) {
      return new MyInfo<T>() { Value = Value, Semantic = Roles.Peek(), Status = InfoStatus.Uniform };
    }
    internal readonly InfoStatus At;
    public EffectEval(InfoStatus At) {
      this.At = At;
      Roles.Push(Semantics.NoRole.Instance);
    }

    public struct Param {
      public int Index;
      public Semantics.Role Semantic;
    }
    public readonly Dictionary<Expr, Param> Params = new Dictionary<Expr, Param>();
    protected override Info<S> AllocateTemp<S>(Scope scope, Info<S> Code) {
      var Code0 = (MyInfo<S>)Code;
      if (Code0.Status != At) return null; // don't memoize.
      (Code0.Value != null).Assert();
      return base.AllocateTemp<S>(scope, Code);
    }
    internal protected abstract void BringIn(MyInfo info0, Expr Expr);
    protected override BaseShaderEval<EVAL>.MyInfo<T> Prepare<T>(Func<BaseShaderEval<EVAL>.MyInfo<T>> Target, Expr[] Exprs, params Eval<EVAL>.Info[] Infos) {
      InfoStatus Status = InfoStatus.Uniform;
      bool IsConstant = true;
      Semantics.Role UseSemantic = Semantics.NoRole.Instance;
      foreach (var info in Infos) {
        var info0 = (MyInfo)info;
        IsConstant = IsConstant && info0.Value != null;
        Status = Merge(Status, info0.Status);
        if (!(info0.Semantic is Semantics.NoRole)) {
          UseSemantic = info0.Semantic;
        }
      }
      // shouldn't be lower than At.
      (((int)Status) >= ((int)At)).Assert();
      if (Status == At) {
        // Bring them all in.
        for (int i = 0; i < Infos.Length; i++) {
          var info0 = (MyInfo)Infos[i];
          if (Exprs != null)
            BringIn(info0, Exprs[i]);
          (info0.Value != null).Assert();
        }
      } else if (!IsConstant) { // an unidentified value, nuke all the other values.
        foreach (var info in Infos)
          ((MyInfo)info).Value = null; // if not null, was a constant!
      }
      var ret = (MyInfo<T>)base.Prepare(Target, Exprs, Infos);
      (ret.Semantic != null).Assert();
      if (ret.Semantic is Semantics.NoRole) ret.Semantic = UseSemantic;
      ret.Status = Status;
      if (ret.Status == At) (ret.Value != null).Assert();
      return ret;
    }
    internal static InfoStatus Merge(InfoStatus s0, InfoStatus s1) {
      return (InfoStatus)Math.Min((int)s0, (int)s1);
    }
  }
  public class Effect<BUFFER> where BUFFER : VertexBuffer<BUFFER> {
    // three kinds of evaluations:
    // (a) inside pixel shader, touches a value that must be used from the pixel shader.
    // (b) inside vertex shader, touches a value that must be used from the vertex shader.
    // (c) outside the shader, touches a value that must be computed outside the shader.
    internal abstract class EffectEval<EVAL> : Shaders.EffectEval<EVAL> where EVAL : Eval<EVAL> {
      private readonly Effect<BUFFER> Outer;
      public EffectEval(Effect<BUFFER> Outer, InfoStatus At) : base(At) {
        this.Outer = Outer;
      }
      internal protected override void BringIn(MyInfo Info, Expr E) {
        if (Info.Status == At || Info.Value != null) {
          Info.Status = At;
          return;
        }
        if (Info.Status == InfoStatus.Uniform) {
          if (!Outer.Uniforms.ContainsKey(E)) { // semantics not important for uniform!
            Outer.Uniforms[E] = Outer.Uniforms.Count;
          }
          Info.Value = "U" + Outer.Uniforms[E];
        } else if (Info.Status == InfoStatus.Vertex) {
          if (!Params.ContainsKey(E)) {
            Params[E] = new Param() {
              Index = Params.Count, Semantic = Info.Semantic,
            };
          }
          //(Params[E].Semantic == Info.Semantic).Assert();
          Info.Value = "input.P" + Params[E].Index;
        } else throw new NotSupportedException();
        Info.Status = At;
      }
    }
    private class EffectEval : EffectEval<EffectEval> {
      public EffectEval(Effect<BUFFER> Outer, InfoStatus At) : base(Outer, At) { }
    }
    // effect for one vertex buffer, can contain multiple techinques. 
    //public readonly VertexBuffer<BUFFER> Buffer;
    // all uniforms are drawn from same place, brought into the pixel or vertex shader directly.  
    private readonly Dictionary<Expr, int> Uniforms = new Dictionary<Expr, int>();
    public Expr[] UniformsOrdered { get; private set; }
    public Semantic[] ParamSemantics { get; private set; }
    public Effect() { }
    public string End() {
      var SemanticMap = new Dictionary<Semantics.Role, int>();
      var output = new System.IO.StringWriter();
      var eval = new EffectEval(this, InfoStatus.Vertex); // just to get type names. 
      UniformsOrdered = new Expr[Uniforms.Count];
      foreach (var uniform in Uniforms) {
        output.WriteLine(eval.TypeNameFor(uniform.Key.TypeOfT) + " U" + uniform.Value + ";");
        UniformsOrdered[uniform.Value] = uniform.Key;
      }
      ParamSemantics = new Semantic[VertexBuffer<BUFFER>.Properties.Count];
      {
        output.WriteLine("struct VS_Input {");
        for (int i = 0; i < VertexBuffer<BUFFER>.PropertiesOrdered.Count; i++) {
          var p = VertexBuffer<BUFFER>.PropertiesOrdered[i];
          ParamSemantics[i] = Allocate(p.TypeOfT, p.Semantic, SemanticMap);
          var tpe = p.TypeOfT;
          if (p == VertexBuffer<BUFFER>.PositionProperty) tpe = typeof(Vec4<double>);


          output.WriteLine("  " + eval.TypeNameFor(tpe) + " " + p.Name + " : " + ParamSemantics[i].ToString() + ";");
        }
        output.WriteLine("};");
      }
      foreach (var v in VertexShaders) output.WriteLine(v.Value.ShaderCode);
      foreach (var p in PixelShaders) {
        output.WriteLine(p.ShaderCode);
        output.WriteLine("technique10 Render" + p.Index + " {");
        output.WriteLine("  pass P0 {");
        output.WriteLine("    SetVertexShader( CompileShader( vs_4_0, VS" + p.VertexShader.Index + "() ) );");
        output.WriteLine("    SetGeometryShader(NULL);");
        output.WriteLine("    SetPixelShader(CompileShader(ps_4_0, PS" + p.Index + "()));");
        output.WriteLine("  }");
        output.WriteLine("}");
      }
      return output.ToString();
    }
    internal class VertexShaderKey { // need to hash pixel shaders.
      public struct Param {
        public Expr Expression;
        public Semantics.Role Semantic;
      }
      public readonly IList<Param> Parameters;
      public readonly Expr<Vec4<double>> UpdatedPosition;
      public VertexShaderKey(IList<Param> Parameters, Expr<Vec4<double>> UpdatedPosition) {
        this.Parameters = Parameters;
        this.UpdatedPosition = UpdatedPosition;
      }
      private int? HashCode;
      public override int GetHashCode() {
        if (HashCode != null) return (int)HashCode;
        int hc = 0;
        foreach (var e in Parameters) hc += e.GetHashCode();
        hc += UpdatedPosition.GetHashCode();
        HashCode = hc;
        return hc;
      }
      public override bool Equals(object obj) {
        var obj0 = obj as VertexShaderKey;
        if (obj0 == null) return base.Equals(obj);
        if (!UpdatedPosition.Equals(obj0.UpdatedPosition)) return false;
        if (Parameters.Count != obj0.Parameters.Count) return false;
        for (int i = 0; i < Parameters.Count; i++) 
          if (!Parameters[i].Equals(obj0.Parameters[i])) return false;
        return true;
      }
    }
    public string Shade(Func<VertexBuffer<BUFFER>.Vertex, ColorBl> ColorF) {
      return "Render" + new PixelShader(this, ColorF).Index;
    }
    private class PixelShader {
      public readonly VertexShader VertexShader;
      public readonly string ShaderCode;
      public readonly int Index;
      public PixelShader(Effect<BUFFER> Outer, Func<VertexBuffer<BUFFER>.Vertex, ColorBl> ColorF) {
        Index = Outer.PixelShaders.Count;
        Outer.PixelShaders.Add(this);
        var vertex = new Vertex0() { Outer = Outer };
        var Color = ColorF(vertex);
        var eval = new EffectEval(Outer, InfoStatus.Pixel);
        var info = (EffectEval.MyInfo<Vec4<double>>)eval.Block("retV", Color.Underlying);
        string OneLine;
        {
          if (info.Status != InfoStatus.Pixel && info.Value == null) { // the color comes directly from the vertex shader!
            eval.BringIn(info, Color.Underlying);
            (info.Value != null && info.BlockBefore == null).Assert();
            OneLine = ("  retV = " + info.Value + ";");
          } else OneLine = null;
          var popped = eval.PopScope();
          (popped.Count == 0 && eval.IsEmpty).Assert();
          // ok, first find the vertex shader.
        }
        {
          var VertexKey = new Effect<BUFFER>.VertexShaderKey(new VertexShaderKey.Param[eval.Params.Count], vertex.UpdatedPosition);
          foreach (var p in eval.Params)
            VertexKey.Parameters[p.Value.Index] = new VertexShaderKey.Param() {
              Expression = p.Key,
              Semantic = p.Value.Semantic,
            };
          // determine shader code + vertex arguments, bring in new uniforms if necessary.
          // after evaluate, find/create VertexShader
          this.VertexShader = Outer.Find(VertexKey);
        }{
          var output = new System.IO.StringWriter();
          output.WriteLine("float4 PS" + Index + "(VS" + VertexShader.Index + "_Output input) : SV_Target {");
          output.WriteLine("  float4 retV;");
          if (OneLine != null)
            output.WriteLine(OneLine);
          else eval.Flatten("  ", info, output);
          output.WriteLine("  return retV;");
          output.WriteLine("}");
          ShaderCode = output.ToString();
        }
        // now we can assign ShaderCode, only body of pixel shader, its input struct is defined by the vertex shader.
      }
    }
    public struct Semantic {
      public string Name; public int Usage;
      public override string ToString() {
        return Name + (Usage == 0 ? "" : Usage.ToString());
      }
    }
    public static Semantic Allocate(Type Type, Semantics.Role Role, Dictionary<Semantics.Role, int> Map) {
      if (Role is Semantics.NoRole) return Allocate(Type, Semantics.TexCoord.Instance, Map);
      if (!Map.ContainsKey(Role)) Map[Role] = 0;
      var Usage = Map[Role];
      Map[Role] = Usage + 1;
      return new Semantic() {
        Name = Role.Name, Usage = Usage,
      };
    }

    public class VertexShader {
      private readonly VertexShaderKey Key; // vertex shader to use.
      public readonly int Index;
      public readonly string ShaderCode;
      public readonly Semantic[] UseSemantics;
      internal VertexShader(Effect<BUFFER> Outer, VertexShaderKey Key) {
        this.Key = Key;
        this.Index = Outer.VertexShaders.Count;
        Outer.VertexShaders[Key] = this;

        var eval = new EffectEval(Outer, InfoStatus.Vertex);
        var Infos = new EffectEval.MyInfo[Key.Parameters.Count + 1];

        // go through each parameter expression + UpdatePosition, assign pixel shader input struct.
        { // updated position.
          Infos[Key.Parameters.Count] = eval.DoEval(Key.UpdatedPosition);
          eval.BringIn(Infos[Key.Parameters.Count], Key.UpdatedPosition);
        }
        for (int i = 0; i < Key.Parameters.Count; i++) {
          Infos[i] = (EffectEval.MyInfo)eval.DoEval(Key.Parameters[i].Expression);
          eval.BringIn(Infos[i], Key.Parameters[i].Expression);
        }
        // grab the temps.
        var output = new System.IO.StringWriter();
        // first...output the...VS[Index]_Output
        output.WriteLine("struct VS" + Index + "_Output {");
        var map = new Dictionary<Semantics.Role, int>();
        //map[Semantics.Position.Instance] = 1;
        UseSemantics = new Semantic[Key.Parameters.Count];
        // add position slot.
        output.WriteLine("  float4 Pos : SV_Position;");
        for (int i = 0; i < Key.Parameters.Count; i++) {
          var e = Key.Parameters[i].Expression;
          var s = Key.Parameters[i].Semantic;
          UseSemantics[i] = Effect<BUFFER>.Allocate(e.TypeOfT, s, map);
          output.WriteLine("  " + eval.TypeNameFor(e.TypeOfT) + " P" + i + " : " + UseSemantics[i].ToString() + ";");
        }
        output.WriteLine("};"); // end VS[Index]_Output
        output.WriteLine("VS" + Index + "_Output VS" + Index + "(VS_Input input) {");
        output.WriteLine("  VS" + Index + "_Output output = (VS" + Index + "_Output) 0;");
        { // dump all the temps first!
          var Temps = eval.PopScope();
          (eval.IsEmpty).Assert();
          foreach (var temp in Temps) {
            var AsTemp = (EffectEval.MyInfo)temp.AsTemp;
            var AsCode = (EffectEval.MyInfo)temp.Code;
            eval.Flatten("  ", AsCode, output);
            output.WriteLine("  " + eval.TypeNameFor(AsTemp.TypeOfT) + " " + AsTemp.Value + " = " + AsCode.Value + ";");
          }
        }
        for (int i = 0; i < Infos.Length; i++) {
          var name = (i < Key.Parameters.Count) ? "P" + i : "Pos";
          output.WriteLine("  output." + name + " = " + Infos[i].Value + ";");
        }
        output.WriteLine("  return output;");
        output.WriteLine("}");
        ShaderCode = output.ToString();
      }
    }
    internal readonly Dictionary<VertexShaderKey, VertexShader> VertexShaders = new Dictionary<VertexShaderKey, VertexShader>();
    private readonly List<PixelShader> PixelShaders = new List<PixelShader>();

    internal VertexShader Find(VertexShaderKey Key) {
      if (VertexShaders.ContainsKey(Key)) return VertexShaders[Key];
      return new VertexShader(this, Key);
    }



    private class Vertex0 : VertexBuffer<BUFFER>.Vertex {
      internal Effect<BUFFER> Outer;
      internal override bool InShader { get { return true; } }
      public override Eval<EVAL>.Info<T> Eval<EVAL, T>(PropertyExpr<VertexBuffer<BUFFER>.Vertex, T> Expr, Eval<EVAL> txt) {
        if (txt is EffectEval<EVAL>) {
          if (Expr.Property == VertexBuffer<BUFFER>.PositionProperty) {
            return new EffectEval<EVAL>.MyInfo<T>() {
              Value = "input.Pos",
              Status = InfoStatus.Vertex,
              Semantic = Semantics.Position.Instance
            };
          } else { // a vertex property
            return new EffectEval<EVAL>.MyInfo<T>() {
              Status = InfoStatus.Vertex,
              Semantic = ((VertexBuffer.IProperty) Expr.Property).Semantic,
              Value = (((EffectEval<EVAL>) txt).At == InfoStatus.Vertex) ? "input." + Expr.Property.Name : null,
            };
          }
        }
        return base.Eval<EVAL, T>(Expr, txt);
      }
      public override int GetHashCode() {
        return typeof(Vertex0).GetHashCode();
      }
      public override bool Equals(object obj) {
        return obj is Vertex0; 
      }
    }

  }
  // force expression to evaluate in pixel shader!
  class PixelExpr<T> : ProxyExpr<T> {
    public PixelExpr(Expr<T> Underlying) : base(Underlying) { }
    protected override ProxyExpr<T> Make(Expr<T> e) {
      return new PixelExpr<T>(e);
    }
    protected override Eval<EVAL>.Info<T> Eval<EVAL>(Eval<EVAL> txt) {
      if (txt is EffectEval<EVAL>) {
        var txt0 = (EffectEval<EVAL>)txt;
        (txt0.At == InfoStatus.Pixel).Assert();
        var info = (EffectEval<EVAL>.MyInfo<T>)txt.DoEval(Underlying);
        txt0.BringIn(info, Underlying);
        (info.Status == InfoStatus.Pixel).Assert();
        return info;
      }
      return base.Eval<EVAL>(txt);
    }
  }
  public static class ShaderExtensions {
    public static BRAND PerPixel<T, BRAND>(this Brand<T, BRAND> Value) where BRAND : Brand<T, BRAND> {
      return Brand<T, BRAND>.ToBrand(new PixelExpr<T>(Value.Underlying));
    }
  }
}